﻿using CPlatePrintSys.Server.Models;
using CPlatePrintSys.Server.Providers;
using CPlatePrintSys.Server.Results;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;

namespace CPlatePrintSys.Server.Controllers
{
    [Authorize]
    [RoutePrefix("api/Account")]
    public class AccountController : ApiController
    {
        private const string LocalLoginProvider = "Local";
        private const string ROLE_SUPER_ADMIN = "SuperAdmin";
        private ApplicationUserManager _userManager;
        private ApplicationRoleManager _roleManager;

        public AccountController()
        {
        }

        public AccountController(ApplicationUserManager userManager,
            ApplicationRoleManager roleManager,
            ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
        {
            UserManager = userManager;
            RoleManager = roleManager;
            AccessTokenFormat = accessTokenFormat;
        }

        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }

        public ApplicationRoleManager RoleManager // <-- 更改了类型
        {
            get
            {
                // 更改 Get<T> 中的泛型参数
                return _roleManager ?? Request.GetOwinContext().Get<ApplicationRoleManager>();
            }
            private set
            {
                _roleManager = value;
            }
        }

        public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }

        // GET api/Account/UserInfo
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("UserInfo")]
        public async Task<UserInfoViewModel> GetUserInfo()
        {
            ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
            // 2. 从 Token 中获取用户 ID
            var userId = User.Identity.GetUserId();
            // 3. 使用 UserManager 异步查询数据库
            var user = await UserManager.FindByIdAsync(userId);
            var roles = await UserManager.GetRolesAsync(userId);
            return new UserInfoViewModel
            {
                id = user.Id,
                Username = User.Identity.GetUserName(),
                Fullname = user.FullName,
                Roles = roles,
                HasRegistered = externalLogin == null,
                LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
            };
        }

        // POST api/Account/Logout
        [Route("Logout")]
        public IHttpActionResult Logout()
        {
            Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
            return Ok();
        }

        // GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
        [Route("ManageInfo")]
        public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
        {
            IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

            if (user == null)
            {
                return null;
            }

            List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();

            foreach (IdentityUserLogin linkedAccount in user.Logins)
            {
                logins.Add(new UserLoginInfoViewModel
                {
                    LoginProvider = linkedAccount.LoginProvider,
                    ProviderKey = linkedAccount.ProviderKey
                });
            }

            if (user.PasswordHash != null)
            {
                logins.Add(new UserLoginInfoViewModel
                {
                    LoginProvider = LocalLoginProvider,
                    ProviderKey = user.UserName,
                });
            }

            return new ManageInfoViewModel
            {
                LocalLoginProvider = LocalLoginProvider,
                Email = user.UserName,
                Logins = logins,
                ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
            };
        }

        // POST api/Account/ChangePassword
        [Route("ChangePassword")]
        public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
                model.NewPassword);
            
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // POST api/Account/SetPassword
        [Route("SetPassword")]
        public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // POST api/Account/AddExternalLogin
        [Route("AddExternalLogin")]
        public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

            AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);

            if (ticket == null || ticket.Identity == null || (ticket.Properties != null
                && ticket.Properties.ExpiresUtc.HasValue
                && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
            {
                return BadRequest("外部登录失败。");
            }

            ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);

            if (externalData == null)
            {
                return BadRequest("外部登录已与某个帐户关联。");
            }

            IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
                new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // POST api/Account/RemoveLogin
        [Route("RemoveLogin")]
        public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result;

            if (model.LoginProvider == LocalLoginProvider)
            {
                result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
            }
            else
            {
                result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
                    new UserLoginInfo(model.LoginProvider, model.ProviderKey));
            }

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // GET api/Account/ExternalLogin
        [OverrideAuthentication]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
        [AllowAnonymous]
        [Route("ExternalLogin", Name = "ExternalLogin")]
        public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
        {
            if (error != null)
            {
                return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
            }

            if (!User.Identity.IsAuthenticated)
            {
                return new ChallengeResult(provider, this);
            }

            ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);

            if (externalLogin == null)
            {
                return InternalServerError();
            }

            if (externalLogin.LoginProvider != provider)
            {
                Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
                return new ChallengeResult(provider, this);
            }

            ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
                externalLogin.ProviderKey));

            bool hasRegistered = user != null;

            if (hasRegistered)
            {
                Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
                
                 ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
                    OAuthDefaults.AuthenticationType);
                ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
                    CookieAuthenticationDefaults.AuthenticationType);

                AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
                Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
            }
            else
            {
                IEnumerable<Claim> claims = externalLogin.GetClaims();
                ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
                Authentication.SignIn(identity);
            }

            return Ok();
        }

        // GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
        [AllowAnonymous]
        [Route("ExternalLogins")]
        public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
        {
            IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
            List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();

            string state;

            if (generateState)
            {
                const int strengthInBits = 256;
                state = RandomOAuthStateGenerator.Generate(strengthInBits);
            }
            else
            {
                state = null;
            }

            foreach (AuthenticationDescription description in descriptions)
            {
                ExternalLoginViewModel login = new ExternalLoginViewModel
                {
                    Name = description.Caption,
                    Url = Url.Route("ExternalLogin", new
                    {
                        provider = description.AuthenticationType,
                        response_type = "token",
                        client_id = Startup.PublicClientId,
                        redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
                        state = state
                    }),
                    State = state
                };
                logins.Add(login);
            }

            return logins;
        }

        //// POST api/Account/Register
        //[AllowAnonymous]
        //[Route("Register")]
        //public async Task<IHttpActionResult> Register(RegisterBindingModel model)
        //{
        //    if (!ModelState.IsValid)
        //    {
        //        return BadRequest(ModelState);
        //    }

        //    var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

        //    IdentityResult result = await UserManager.CreateAsync(user, model.Password);

        //    if (!result.Succeeded)
        //    {
        //        return GetErrorResult(result);
        //    }

        //    return Ok();
        //}

        // POST api/Account/RegisterExternal
        [OverrideAuthentication]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RegisterExternal")]
        public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var info = await Authentication.GetExternalLoginInfoAsync();
            if (info == null)
            {
                return InternalServerError();
            }

            var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

            IdentityResult result = await UserManager.CreateAsync(user);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            result = await UserManager.AddLoginAsync(user.Id, info.Login);
            if (!result.Succeeded)
            {
                return GetErrorResult(result); 
            }
            return Ok();
        }

        /// <summary>
        /// [Admin] 获取所有用户的列表 (支持分页)
        /// </summary>
        [HttpGet]
        [Route("GetUsers")]
        [Authorize(Roles = "SuperAdmin")]
        // 1. 使用 [FromUri] 绑定分页参数
        public async Task<IHttpActionResult> GetUsers([FromUri] PagingParameters pagingParams)
        {
            // 2. 使用 IQueryable 以便数据库进行分页
            var query = UserManager.Users;

            // 3. 获取总数 (在分页前)
            int totalCount = await query.CountAsync();

            // 4. 应用排序 (分页必须有排序) 和分页
            var users = await query.OrderBy(u => u.UserName)
                                   .Skip((pagingParams.PageNumber - 1) * pagingParams.PageSize)
                                   .Take(pagingParams.PageSize)
                                   .ToListAsync();

            var userViewModels = new List<AdminUserViewModel>();

            // 5. 转换数据 (注意: 这里的 GetRolesAsync 是 N+1 查询, 
            //    对于分页(N=PageSize)来说通常是可接受的)
            foreach (var user in users)
            {
                var vm = new AdminUserViewModel
                {
                    Id = user.Id,
                    UserName = user.UserName,
                    Email = user.Email,
                    FullName = user.FullName, // 假设您的 ApplicationUser 有此属性
                    IsLockedOut = await UserManager.IsLockedOutAsync(user.Id),
                    Roles = await UserManager.GetRolesAsync(user.Id)
                };
                userViewModels.Add(vm);
            }

            // 6. 创建并返回 PagedResultViewModel
            var pagedResult = new PagedResultViewModel<AdminUserViewModel>(
                userViewModels,
                pagingParams.PageNumber,
                pagingParams.PageSize,
                totalCount
            );

            return Ok(pagedResult);
        }

        /// <summary>
        /// [Admin] 创建一个新用户
        /// </summary>
        [HttpPost]
        [Route("CreateUser")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> CreateUser(AdminCreateUserModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var user = new ApplicationUser()
            {
                UserName = model.UserName,
                Email = model.Email,
                FullName = model.FullName 
            };

            IdentityResult result = await UserManager.CreateAsync(user, model.Password);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            // (可选) 分配角色
            if (model.Roles != null && model.Roles.Any())
            {
                await UserManager.AddToRolesAsync(user.Id, model.Roles.ToArray());
            }

            return Ok();
        }

        /// <summary>
        /// [Admin] 删除一个用户
        /// </summary>
        /// <param name="id">用户ID</param>
        [HttpDelete]
        [Route("DeleteUser/{id}")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> DeleteUser(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return BadRequest("用户ID不能为空。");
            }

            // 防止管理员删除自己
            if (id == User.Identity.GetUserId())
            {
                return BadRequest("管理员不能删除自己的帐户。");
            }

            var user = await UserManager.FindByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }

            IdentityResult result = await UserManager.DeleteAsync(user);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        /// <summary>
        /// [Admin] 更新用户信息 (不包括密码)
        /// </summary>
        /// <param name="id">用户ID</param>
        /// <param name="model">用户信息</param>
        [HttpPut]
        [Route("UpdateUser/{id}")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> UpdateUser(string id, AdminUpdateUserModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            // 防止修改管理员账户
            if (id == User.Identity.GetUserId())
            {
                return BadRequest("不能管理员帐户。");
            }

            var user = await UserManager.FindByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }

            // 更新基本信息
            user.Email = model.Email;
            user.UserName = model.Email; // 通常保持 Email 和 UserName 同步
            user.FullName = model.FullName;
            user.PhoneNumber = model.PhoneNumber;

            IdentityResult updateResult = await UserManager.UpdateAsync(user);
            if (!updateResult.Succeeded)
            {
                return GetErrorResult(updateResult);
            }

            // 更新角色
            if (model.Roles != null)
            {
                var currentRoles = await UserManager.GetRolesAsync(user.Id);
                var rolesToRemove = currentRoles.Except(model.Roles).ToArray();
                var rolesToAdd = model.Roles.Except(currentRoles).ToArray();

                if (rolesToRemove.Any())
                {
                    await UserManager.RemoveFromRolesAsync(user.Id, rolesToRemove);
                }

                if (rolesToAdd.Any())
                {
                    await UserManager.AddToRolesAsync(user.Id, rolesToAdd);
                }
            }

            return Ok();
        }

        /// <summary>
        /// [Admin] 重置指定用户的密码
        /// </summary>
        [HttpPost]
        [Route("ResetPassword")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> ResetPassword(AdminResetPasswordModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var user = await UserManager.FindByIdAsync(model.UserId);
            if (user == null)
            {
                return NotFound();
            }

            // 不能用这个接口重置自己的密码
            if (user.Id == User.Identity.GetUserId())
            {
                return BadRequest("请使用 'ChangePassword' 接口修改您自己的密码。");
            }

            // 强制重置密码最可靠的方法是移除旧密码(如果存在)，再添加新密码
            // 这比使用 token 更直接

            // 1. 移除旧密码
            // (如果用户已通过外部登录注册，可能没有本地密码)
            if (await UserManager.HasPasswordAsync(user.Id))
            {
                IdentityResult removeResult = await UserManager.RemovePasswordAsync(user.Id);
                if (!removeResult.Succeeded)
                {
                    return GetErrorResult(removeResult);
                }
            }

            // 2. 添加新密码
            IdentityResult addResult = await UserManager.AddPasswordAsync(user.Id, model.NewPassword);
            if (!addResult.Succeeded)
            {
                return GetErrorResult(addResult);
            }

            return Ok();
        }

        /// <summary>
        /// [Admin] 解除用户锁定
        /// </summary>
        /// <param name="id">用户ID</param>
        [HttpPost]
        [Route("UnlockUser/{id}")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> UnlockUser(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return BadRequest("用户ID不能为空。");
            }

            var user = await UserManager.FindByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }

            if (!(await UserManager.IsLockedOutAsync(id)))
            {
                return Ok("用户未被锁定。");
            }

            // 通过将锁定结束日期设置为 "现在" 来解除锁定
            IdentityResult result = await UserManager.SetLockoutEndDateAsync(id, DateTimeOffset.UtcNow);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            // 重置失败登录次数
            await UserManager.ResetAccessFailedCountAsync(id);

            return Ok("用户已解锁。");
        }

        /// <summary>
        /// [Admin] 获取所有角色的列表
        /// </summary>
        [HttpGet]
        [Route("GetRoles")]
        [Authorize(Roles = ROLE_SUPER_ADMIN)]
        public async Task<IHttpActionResult> GetRoles()
        {
            // 4. 实现 GetRoles
            var roles = await RoleManager.Roles.Select(r => new RoleViewModel
            {
                Id = r.Id,
                Name = r.Name
            }).ToListAsync();

            return Ok(roles);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && _userManager != null)
            {
                _userManager.Dispose();
                _userManager = null;
            }

            base.Dispose(disposing);
        }

        #region 帮助器

        private IAuthenticationManager Authentication
        {
            get { return Request.GetOwinContext().Authentication; }
        }

        private IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (!result.Succeeded)
            {
                if (result.Errors != null)
                {
                    foreach (string error in result.Errors)
                    {
                        ModelState.AddModelError("", error);
                    }
                }

                if (ModelState.IsValid)
                {
                    // 没有可发送的 ModelState 错误，因此仅返回空 BadRequest。
                    return BadRequest();
                }

                return BadRequest(ModelState);
            }

            return null;
        }

        private class ExternalLoginData
        {
            public string LoginProvider { get; set; }
            public string ProviderKey { get; set; }
            public string UserName { get; set; }

            public IList<Claim> GetClaims()
            {
                IList<Claim> claims = new List<Claim>();
                claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));

                if (UserName != null)
                {
                    claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
                }

                return claims;
            }

            public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
            {
                if (identity == null)
                {
                    return null;
                }

                Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);

                if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
                    || String.IsNullOrEmpty(providerKeyClaim.Value))
                {
                    return null;
                }

                if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
                {
                    return null;
                }

                return new ExternalLoginData
                {
                    LoginProvider = providerKeyClaim.Issuer,
                    ProviderKey = providerKeyClaim.Value,
                    UserName = identity.FindFirstValue(ClaimTypes.Name)
                };
            }
        }

        private static class RandomOAuthStateGenerator
        {
            private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();

            public static string Generate(int strengthInBits)
            {
                const int bitsPerByte = 8;

                if (strengthInBits % bitsPerByte != 0)
                {
                    throw new ArgumentException("strengthInBits 必须能被 8 整除。", "strengthInBits");
                }

                int strengthInBytes = strengthInBits / bitsPerByte;

                byte[] data = new byte[strengthInBytes];
                _random.GetBytes(data);
                return HttpServerUtility.UrlTokenEncode(data);
            }
        }

        #endregion
    }
}
